// SPDX-License-Identifier: GPL-2.0-or-later
/* Module signature checker
 *
 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/module_signature.h>
#include <linux/string.h>
#include <linux/verification.h>
#include <crypto/public_key.h>
#include "module-internal.h"
#if (defined CONFIG_RTOS_MODULE_CERT_REVOCATE) || (defined CONFIG_EULEROS_SIGNATURE_PSS)
#include <linux/crl_revocate.h>
#endif
#ifdef CONFIG_RTOS_MODULE_DIGESTLIST
#include <internal/rtos_module_digest.h>
#endif

#ifdef CONFIG_EULEROS_USE_PLATFORM_KEY
static int mod_use_platform_verify_data(const void *mod, unsigned long modlen,
		const void *sig, size_t sig_len)
{
	int ret = 0;
#ifdef CONFIG_EULEROS_CMS_CBB
	ret = mod_verify_cms_data(mod, modlen, sig, sig_len);
#else
	ret = verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
			VERIFY_USE_SECONDARY_KEYRING,
			VERIFYING_MODULE_SIGNATURE,
			NULL, NULL);
#endif
	if (ret && IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING)) {
		ret =  verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
				VERIFY_USE_PLATFORM_KEYRING,
				VERIFYING_MODULE_SIGNATURE, NULL, NULL);
	}
	return ret;
}
#endif

/*
 * Verify the signature on a module.
 */
int mod_verify_sig(const void *mod, struct load_info *info)
{
	struct module_signature ms;
	size_t sig_len, modlen = info->len;
	int ret;

	pr_devel("==>%s(,%zu)\n", __func__, modlen);

	if (modlen <= sizeof(ms))
		return -EBADMSG;

	memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));

	ret = mod_check_sig(&ms, modlen, "module");
	if (ret)
		return ret;

	sig_len = be32_to_cpu(ms.sig_len);
	modlen -= sig_len + sizeof(ms);
	info->len = modlen;
#ifdef CONFIG_RTOS_MODULE_SIG_VERIFY
	if (!is_module_sig_enforced())
		return 0;
#endif

#ifdef CONFIG_RTOS_MODULE_DIGESTLIST
	if (module_found_digest(mod, modlen, sig_len))
		return 0;
#endif

#if defined(CONFIG_RTOS_MODULE_CERT_REVOCATE)
	return kernel_verify_cms_data(mod, modlen, mod + modlen, sig_len);
#elif defined(CONFIG_EULEROS_USE_PLATFORM_KEY)
	return mod_use_platform_verify_data(mod, modlen, mod + modlen, sig_len);
#else
	return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
				      VERIFY_USE_SECONDARY_KEYRING,
				      VERIFYING_MODULE_SIGNATURE,
				      NULL, NULL);
#endif
}
